﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using App1AppHandler;
using System.Drawing;
using System.Timers;
using Reborn_WorldServer;

namespace Reborn_Server.App1AppHandler
{
    public class Spell_Fear : Buff, IAIBuff
    {
        public Spell_Fear() 
        {
            spellTimer.Interval = 3000;
            minutesLeft = -2;
            ticksLeft = 5;
        }

        override public void Resume(CreatureBase targetCreatureBase, SpellIcon _spellIcon, int timeRemaining, int castLevel, int castCharacterID, int castInt, int castWis, int optionalValue, string xmlData)
        {
            ticksLeft = timeRemaining;
            base.Resume(targetCreatureBase, _spellIcon, timeRemaining, castLevel, castCharacterID, castInt, castWis, optionalValue, xmlData);
            

            if (TargetCreatureBase is Character)
            {
                Character targetCharacter = (Character)TargetCreatureBase;
                targetCharacter.SetBusy(true);

                //If character is waiting for round to expire, spell needs to wait
                if (targetCharacter.Timer_Round_IsRunning == true)
                {
                    //Handler to fire after round timer has elapsed
                    targetCharacter.RoundElapsed += new Character.TimerElapsedHandler(targetCharacter_RoundElapsed);
                }
                //Character is not waiting for round, start spell immediately
                else
                {
                    //Start Spell
                    targetCharacter.StartAI();
                }
            }

            base.spellTimer.Start();
        }

        public override bool tryResist(SpellIcon _spellIcon, int castLevel, int castInt, int castWis, CreatureBase targetCreatureBase)
        {
            int penetration = SkillManager.AdjustForCombat(castLevel, 0, castInt);

            int resist = 0;
            if (_spellIcon.Name.IndexOf("Rank 2") > -1)
                resist = System.Convert.ToInt32(targetCreatureBase.getResist(_spellIcon.Skill) * 1.5);
            else
                resist = targetCreatureBase.getResist(_spellIcon.Skill) * 2;

            int result = Managers.GameHandler.random.Next(1, penetration + resist + 1);
            if (result > penetration)
                return true;

            return false;
        }

        public void Cast(CreatureBase myCreatureBase, int CastLevel, long CreatureGUID)
        {
            List<MapItem> MapItemsWithin12;
            if (base.InitializeCast(myCreatureBase, CastLevel, CreatureGUID, true, out MapItemsWithin12) == false)
                return;

            TargetCreatureBase.buffManager.UpdateBuffs();

            if (TargetCreatureBase is Character)
            {
                Character targetCharacter = (Character)TargetCreatureBase;
                targetCharacter.SetBusy(true);

                //If character is waiting for round to expire, spell needs to wait
                if (targetCharacter.Timer_Round_IsRunning == true)
                {
                    //Handler to fire after round timer has elapsed
                    targetCharacter.RoundElapsed += new Character.TimerElapsedHandler(targetCharacter_RoundElapsed);
                }
                //Character is not waiting for round, start spell immediately
                else
                {
                    //Start Spell
                    targetCharacter.StartAI();
                }
            }
            
            base.spellTimer.Start();
        }
        private void targetCharacter_RoundElapsed(object sender)
        {
            Character character = (Character)base.TargetCreatureBase;
            //Remove handler, we dont want to restart the spell after the next round
            character.RoundElapsed -= new Character.TimerElapsedHandler(targetCharacter_RoundElapsed);

            character.StartAI();
        }
        public override void RemoveSpell(bool updateBuffs, bool sendMessage)
        {
            //Remove the spell from the buff window, stop the timer, send out messages
            base.RemoveSpell(updateBuffs, sendMessage);

            //If creature is character remove busy counter from character
            if (TargetCreatureBase is Character)
            {
                Character targetCharacter = (Character)TargetCreatureBase;
                targetCharacter.SetBusy(false);
            }
        }

        public int runAI()
        {
            LockItem lockItem = TargetCreatureBase.GameHandler.GetLockItem(TargetCreatureBase.MapID, TargetCreatureBase.Instance);
            lock (lockItem.LockObj)
            {
                if (TargetCreatureBase.buffManager.IsStunned() == true || TargetCreatureBase.HP < 1)
                    return 3000;

                //Determine maximum moves
                int MaxMoves = 4;
                if (TargetCreatureBase is Creature)
                {
                    Creature creature = (Creature)TargetCreatureBase;
                    MaxMoves = creature.MaxMoves;
                }

                //GET AVAILABLE PATHS
                List<List<MapItem>> Paths = CreatureAI.FindAllPaths(TargetCreatureBase, TargetCreatureBase.currentMapItem.mapItemsWithin4, TargetCreatureBase.currentMapItem);

                //Find max distance in calculated paths
                int MaxDistanceInAvailablePaths = 0;
                foreach (List<MapItem> path in Paths)
                {
                    MapItem LastItem = path[path.Count - 1];
                    int Xdistance = Math.Abs(TargetCreatureBase.MapX - LastItem.MapX);
                    int Ydistance = Math.Abs(TargetCreatureBase.MapY - LastItem.MapY);
                    int MaxDistance = Math.Max(Xdistance, Ydistance);

                    if (MaxDistance > MaxDistanceInAvailablePaths)
                        MaxDistanceInAvailablePaths = MaxDistance;
                }

                //Tracks paths with same end position so we dont bias in one direction
                List<Point> UsedLocations = new List<Point>();
                //Find paths that are at max distance
                List<List<MapItem>> PathsAtMaxDistance = new List<List<MapItem>>();
                foreach (List<MapItem> path in Paths)
                {
                    MapItem LastItem = path[path.Count - 1];
                    int Xdistance = Math.Abs(TargetCreatureBase.MapX - LastItem.MapX);
                    int Ydistance = Math.Abs(TargetCreatureBase.MapY - LastItem.MapY);

                    if (Xdistance == MaxDistanceInAvailablePaths || Ydistance == MaxDistanceInAvailablePaths)
                    {
                        bool LocationAvailable = true;
                        foreach (Point location in UsedLocations)
                        {
                            if (location.X == LastItem.MapX && location.Y == LastItem.MapY)
                            {
                                LocationAvailable = false;
                                break;
                            }
                        }
                        if (LocationAvailable == true)
                        {
                            UsedLocations.Add(new Point(LastItem.MapX, LastItem.MapY));
                            PathsAtMaxDistance.Add(path);
                        }
                    }
                }

                //Choose a random path out of paths at max distance
                int PathToChoose = base.TargetCreatureBase.GameHandler.random.Next(PathsAtMaxDistance.Count);
                List<MapItem> ChosenPath = PathsAtMaxDistance[PathToChoose];
                
                //MapItem that we will stop on
                MapItem LandingMapItem = null;
                
                //Move through path and make modifications (Open doors, restrict motion per hex type [water, sand, etc])
                int NumMovesAvailable = ChosenPath.Count;
                if (ChosenPath.Count > MaxMoves + 1)
                    NumMovesAvailable = MaxMoves + 1;

                int LandingIndex = 0;
                List<int> indexesToUpdate = new List<int>();
                for (int x = 1; x < NumMovesAvailable; x++)
                {
                    MapItem mapitem = ChosenPath[x];
                    LandingIndex = x;

                    if (mapitem.Motion + 1 < NumMovesAvailable)
                    {
                        NumMovesAvailable = mapitem.Motion + 1;
                    }
                    if (mapitem.TerrainType == "Door")
                    {
                        if (mapitem.TerrainUrl.IndexOf("Closed") > 0)
                        {
                            mapitem.Transparent = true;
                            mapitem.TerrainUrl = mapitem.TerrainUrl.Replace("Closed", "Open");
                            indexesToUpdate.Add(x);

                            //Play Door Open
                        }
                    }
                }

                //get the last position in the chosen path
                LandingMapItem = ChosenPath[LandingIndex];

                //Non refresh updates for non target creatures
                List<MapItem> MapItemsToUpdate = new List<MapItem>();
                MapItemsToUpdate.Add(TargetCreatureBase.currentMapItem);

                for (int x = 1; x < ChosenPath.Count; x++)
                {
                    bool itemAdded = false;
                    foreach (int index in indexesToUpdate)
                    {
                        if (x == index)
                        {
                            MapItemsToUpdate.Add(ChosenPath[x]);
                            itemAdded = true;
                            break;
                        }
                    }
                    if (x == LandingIndex)
                    {
                        if (itemAdded == false)
                            MapItemsToUpdate.Add(ChosenPath[x]);
                        break;
                    }
                }

                //Characters within range of starting or ending position
                List<Character> CharactersToUpdate = new List<Character>();

                //Refresh Screen updates for target creature
                foreach (MapItem mapitem in TargetCreatureBase.currentMapItem.mapItemsWithin12)
                {
                    if ((Math.Abs(TargetCreatureBase.currentMapItem.MapX - mapitem.MapX) <= 8 && Math.Abs(TargetCreatureBase.currentMapItem.MapY - mapitem.MapY) <= 8) ||
                        (Math.Abs(LandingMapItem.MapX - mapitem.MapX) <= 8 && Math.Abs(LandingMapItem.MapY - mapitem.MapY) <= 8))
                    {
                        foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                        {
                            if (creaturebase is Character)
                                CharactersToUpdate.Add((Character)creaturebase);
                        }
                    }
                }

                TargetCreatureBase.currentMapItem.CreaturesBases.Remove(TargetCreatureBase);
                TargetCreatureBase.SetPosition(LandingMapItem);
                LandingMapItem.CreaturesBases.Add(TargetCreatureBase);

                if (TargetCreatureBase is Character)
                {
                    Character character = (Character)base.TargetCreatureBase;
                    //Update Character 
                    character.Update_Character();

                    //Update Characters Screen (with refresh)
                    character.AddMapItems(LandingMapItem.mapItemsWithin8, true);
                }
                foreach (Character character in CharactersToUpdate)
                {
                    if (character != base.TargetCreatureBase)
                        character.AddMapItems(MapItemsToUpdate, false);
                }
            }
            return 3000;
        }

        protected override void SpellTimer_Expired(object source, ElapsedEventArgs e)
        {
            LockItem lockitem = TargetCreatureBase.GameHandler.GetLockItem(TargetCreatureBase.MapID, TargetCreatureBase.Instance);

            lock (lockitem.LockObj)
            {
                //This buff has been removed, do nothing (this can occur if the buff gets overwritten exactly when this timer fires)
                if (TargetCreatureBase.buffManager.hasBuff(this.SpellID) == false)
                    return;

                if (ticksLeft > 0)
                {
                    ticksLeft--;
                    spellTimer.Start();
                }
                else
                    RemoveSpell(true, true);
            }
        }
    }
}
